package com.shareyi.baseproject.kernel.adapter.spi.sequence;

import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;

/**
 * 58,34进制转换工具
 * 0-10、a-z、A-Z，去除不好辨识的字符，例如大写O、小写l等，共凑成58个字符数组。传入long型数据，递归对58进行取模取余，进行进制转换
 *
 * @author david
 * @date 2021-06-02
 */
public class SequenceEncodeUtils {


    /**
     * 最小支持的进制
     */
    private static final int MIN_SCALE = 2;
    /**
     * 34进制，仅保留数字，大写字母，排期容易混淆的字符；用于大小写不敏感的场景；
     */
    public static final int DEFAULT_SHORT_SCALE = 34;
    /**
     * 58进制，数字，大小写 ，排除容易混淆的字符；
     */
    public static final int DEFAULT_LONG_SCALE = 58;
    /**
     * 解码用的map
     */
    private static final HashMap<String, Integer> DECODE_CHAR_MAP = new HashMap<String, Integer>();

    /**
     * 58进制编码表，去掉 oOIl
     */
    private static final char[] charArray = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz".toCharArray();

    /**
     * 解码值放入map
     */
    static {
        for (int i = 0, length = charArray.length; i < length; i++) {
            DECODE_CHAR_MAP.put(String.valueOf(charArray[i]), i);
        }
    }

    /**
     * 编码为字符串
     *
     * @param num   数字
     * @param scale 进制
     * @return
     */
    public static String encodeStr(Long num, int scale) {
        checkScale(scale);
        StringBuilder sb = new StringBuilder();
        while (num != 0) {
            sb.append(charArray[(int) (num % scale)]);
            num = num / scale;
        }
        return sb.toString();
    }

    /**
     * 验证scale 参数是否合法
     *
     * @param scale
     */
    private static void checkScale(int scale) {
        if (scale < MIN_SCALE || scale > DEFAULT_LONG_SCALE) {
            throw new IllegalArgumentException("scale must between " + MIN_SCALE + " to " + DEFAULT_LONG_SCALE);
        }
    }

    /**
     * 解码字符串
     *
     * @param str
     * @param scale
     * @return
     */
    public static long decodeStr(String str, int scale) {
        checkScale(scale);
        long sum = 0;
        if (StringUtils.isEmpty(str)) {
            return sum;
        }
        for (int i = str.length() - 1; i >= 0; i--) {
            Integer mapNumber = DECODE_CHAR_MAP.get(str.charAt(i) + "");
            if (mapNumber == null || mapNumber > scale) {
                throw new IllegalArgumentException("解码字符串中含有非法字符");
            }
            sum += Math.pow(scale, i) * mapNumber;
        }
        return sum;
    }
}
